home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_200
/
247_03
/
williams.c
< prev
next >
Wrap
Text File
|
1989-04-17
|
6KB
|
178 lines
/*
* Program to factor big numbers using Williams (p+1) method.
* Works when for some prime divisor p of n, p+1 has only
* small factors.
* See "Speeding the Pollard and Elliptic Curve Methods"
* by Peter Montgomery, Math. Comp. Vol. 48. Jan. 1987 pp243-264
*/
#include <stdio.h>
#include "miracl.h"
#define LIMIT1 4000 /* must be int, and > MULT/2 */
#define LIMIT2 200000L /* may be long */
#define MULT 2310 /* must be int, product of small primes 2.3.. */
#define NTRYS 3 /* number of attempts */
big t,t2;
void lucas(p,r,n,vp,v)
big p,v,n,vp;
int r;
{ /* calculate r-th elements of lucas sequence mod n */
int k,rr;
convert(2,vp);
copy(p,v);
subtract(n,p,p);
k=1;
rr=r;
while ((rr/=2)>1) k*=2;
while (k>0)
{ /* use binary method */
mad(v,vp,p,n,n,vp);
mad(v,v,t2,n,n,v);
if ((r&k)>0)
{
mad(p,v,vp,n,n,t);
copy(v,vp);
negate(t,v);
}
k/=2;
}
subtract(n,p,p);
}
main()
{ /* factoring program using Williams (p+1) method */
int k,phase,m,nt,iv,pos,btch;
int *primes;
long i,p,pa;
big b,q,n,fp,fvw,fd,fn;
static big fu[1+MULT/2];
static bool cp[1+MULT/2];
mirsys(50,MAXBASE);
b=mirvar(0);
t2=mirvar((-2));
q=mirvar(0);
n=mirvar(0);
t=mirvar(0);
fp=mirvar(0);
fvw=mirvar(0);
fd=mirvar(0);
fn=mirvar(0);
primes=gprime(LIMIT1);
for (m=1;m<=MULT/2;m+=2)
if (igcd(MULT,m)==1)
{
fu[m]=mirvar(0);
cp[m]=TRUE;
}
else cp[m]=FALSE;
printf("input number to be factored\n");
cinnum(n,stdin);
if (prime(n))
{
printf("this number is prime!\n");
exit(0);
}
for (nt=0,k=3;k<10;k++)
{ /* try more than once for p+1 condition (may be p-1) */
convert(k,b); /* try b=3,4,5.. */
convert((k*k-4),t);
if (gcd(t,n,t)!=1) continue; /* check (b*b-4,n)!=0 */
nt++;
phase=1;
p=0;
btch=50;
i=0;
printf("phase 1 - trying all primes less than %d\n",LIMIT1);
printf("prime= %8ld",p);
forever
{ /* main loop */
if (phase==1)
{ /* looking for all factors of p+1 < LIMIT1 */
p=primes[i];
if (primes[i+1]==0)
{ /* now change gear */
phase=2;
printf("\nphase 2 - trying last prime less than %ld\n"
,LIMIT2);
printf("prime= %8ld",p);
copy(b,fu[1]);
copy(b,fp);
mad(b,b,t2,n,n,fd);
negate(b,t);
mad(fd,b,t,n,n,fn);
for (m=5;m<=MULT/2;m+=2)
{ /* store fu[m] = Vm(b) */
negate(fp,t);
mad(fn,fd,t,n,n,t);
copy(fn,fp);
copy(t,fn);
if (!cp[m]) continue;
copy(t,fu[m]);
}
lucas(b,MULT,n,fp,fd);
iv=p/MULT;
if (p%MULT>MULT/2) iv++,p=2*(long)iv*MULT-p;
lucas(fd,iv,n,fp,fvw);
negate(fp,fp);
subtract(fvw,fu[p%MULT],q);
btch*=10;
i++;
continue;
}
pa=p;
while ((LIMIT1/p) > pa) pa*=p;
lucas(b,(int)pa,n,fp,q);
copy(q,b);
decr(q,2,q);
}
else
{ /* phase 2 - looking for last large prime factor of (p+1) */
p+=2;
pos=p%MULT;
if (pos>MULT/2)
{ /* increment giant step */
iv++;
p=(long)iv*MULT+1;
pos=1;
copy(fvw,t);
mad(fvw,fd,fp,n,n,fvw);
negate(t,fp);
}
if (!cp[pos]) continue;
subtract(fvw,fu[pos],t);
mad(q,t,t,n,n,q); /* batching gcds */
}
if (i++%btch==0)
{ /* try for a solution */
printf("\b\b\b\b\b\b\b\b%8ld",p);
gcd(q,n,t);
if (size(t)==1)
{
if (p>LIMIT2) break;
else continue;
}
if (compare(t,n)==0)
{
printf("\ndegenerate case");
break;
}
printf("\nfactors are\n");
if (prime(t)) printf("prime factor ");
else printf("composite factor ");
cotnum(t,stdout);
divide(n,t,n);
if (prime(n)) printf("prime factor ");
else printf("composite factor ");
cotnum(n,stdout);
exit(0);
}
}
if (nt>=NTRYS) break;
printf("\ntrying again\n");
}
printf("\nfailed to factor\n");
}